﻿using System;
using System.Collections.Generic;
using System.Data;
using System.Globalization;
using System.IO;
using System.Linq;
using System.Net;
using System.Security.Permissions;
using System.Text;
using System.Web;
using System.Web.Script.Services;
using System.Web.Services;
using System.Web.UI;
using System.Web.UI.WebControls;
using DataObject.DataAccess;
using DataObject.Database;
using DataObject.Model;

namespace TreasureJunk
{
    /// <summary>
    ///     Summary description for GetService
    /// </summary>
    [WebService(Namespace = "http://tempuri.org/")]
    [WebServiceBinding(ConformsTo = WsiProfiles.BasicProfile1_1)]
    // To allow this Web Service to be called from script, using ASP.NET AJAX, uncomment the following line. 
    // [System.Web.Script.Services.ScriptService]
    [ScriptService]
    public class Get : WebService
    {
        #region Constructors & Destructors

        #endregion

        [WebMethod(true, EnableSession = true)]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public object QuickSearch(string keyword)
        {
            return new ReservationDAO().GetQuickSearch(keyword);
        }

        [WebMethod(true, EnableSession = true)]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public object GetSticky(string date)
        {
            // get from DB
            DateTime stickyDate;
            if (!DateTime.TryParse(date, CultureInfo.InvariantCulture, DateTimeStyles.None, out stickyDate))
            {
                return String.Empty;
            }

            return StickyDAO.CreateInstant().GetStickyByDate(stickyDate).Description;
        }

        #region Get Exchange

        [WebMethod(true, EnableSession = true)]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public object GetExchange(string code, string date = null)
        {
            try
            {
                string key = String.Empty;
                DateTime dateTime;

                // Create key for the session of exchange rate
                if (DateTime.TryParse(date, CultureInfo.InvariantCulture, DateTimeStyles.None, out dateTime))
                {
                    key = dateTime.ToShortDate().Replace('/', '_');
                }

                IList<ExchangeRate> exchangeRates;

                if (Context.Session != null && Context.Session["ExchangeRate" + key] != null)
                {
                    // Available
                    exchangeRates = Context.Session["ExchangeRate" + key] as IList<ExchangeRate>;
                }
                else
                {
                    // Get from DB
                    DateTime rateDate;
                    if (!DateTime.TryParse(date, CultureInfo.InvariantCulture, DateTimeStyles.None, out rateDate))
                        rateDate = DateTime.Now;
                    exchangeRates = ExchangeRateDAO.CreateInstant().GetList(rateDate);
                    if (exchangeRates != null)
                    {
                        // Get from DB
                        if (Context.Session != null)
                        {
                            Context.Session["ExchangeRate" + date] = exchangeRates;
                            Context.Session["ratesite"] = "Exchange: (local)";
                        }
                    }
                    else
                    {
                        // Get Exchange Rate on Bank Site
                        foreach (string site in define.RateSites)
                        {
                            string html = GetExchangeLink(site);
                            int index = html.IndexOf(">USD<", StringComparison.Ordinal);
                            if (index > 0)
                            {
                                int indexStart = html.Substring(0, index)
                                    .LastIndexOf("<table", StringComparison.Ordinal);
                                html = html.Remove(0, indexStart);
                                int indexEnd = html.IndexOf("</table>", StringComparison.Ordinal) + "</table>".Length;
                                html = html.Remove(indexEnd);

                                DataTable table = HtmlTableParser.ParseTable(html);
                                if (table != null && table.Rows.Count > 0)
                                {
                                    int idxUnitPrice = table.Columns.Count - 2; // get ty gia chuyen khoan

                                    exchangeRates = new List<ExchangeRate>
                                    {
                                        new ExchangeRate {Code = "VND", UnitPrice = 1}
                                    };
                                    foreach (DataRow item in table.Rows)
                                    {
                                        if (DropDownListHelper.Currencies.Count(x => x.Text == item[0].ToString()) > 0)
                                            exchangeRates.Add(new ExchangeRate
                                            {
                                                Code = item[0].ToString(),
                                                UnitPrice = Convert.ToDecimal(item[idxUnitPrice])
                                            });
                                    }

                                    // Write Exchange Rate List
                                    ExchangeRateDAO.CreateInstant().WriteList(rateDate, exchangeRates);
                                    if (Context.Session != null) Context.Session["ExchangeRate" + key] = exchangeRates;
                                }
                                if (Context.Session != null) Context.Session["ratesite"] = "Exchange: " + site;
                                break;
                            }
                        }
                    }
                }
                if (exchangeRates != null)
                    return exchangeRates.SingleOrDefault(x => x.Code == code);
                return new ExchangeRate {Code = "VND", UnitPrice = 1};
            }
            catch (Exception)
            {
                throw new NullReferenceException("Test");
            }
        }

        [WebMethod(true, EnableSession = true)]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public object GetCash(string code)
        {
            ExchangeRate rate;
            switch (code)
            {
                case "USD":
                    rate = new ExchangeRate {Code = "USD", UnitPrice = 21000};
                    break;
                case "EUR":
                    rate = new ExchangeRate {Code = "EUR", UnitPrice = 28000};
                    break;
                default:
                    rate = new ExchangeRate {Code = "VND", UnitPrice = 1};
                    break;
            }
            return rate;
        }

        private string GetExchangeLink(string link)
        {
            string content = string.Empty;

            try
            {
                WebRequest objWebRequest = WebRequest.Create(link);
                objWebRequest.Credentials = CredentialCache.DefaultCredentials;
                WebResponse objWebResponse = objWebRequest.GetResponse();
                Stream receiveStream = objWebResponse.GetResponseStream();
                if (receiveStream != null)
                {
                    var readStream = new StreamReader(receiveStream, Encoding.UTF8);
                    content = readStream.ReadToEnd();
                    objWebResponse.Close();
                    readStream.Close();
                }
            }
            catch (Exception ex)
            {
                return ex.Message;
            }

            return content;
        }

        #endregion

        #region Calendar

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public object FetchAgentList(string agentid)
        {
            // Get Price
            var fetchAgent = GuestDAO.CreateInstant().FetchAgentList(agentid)
                .Select(item => new
                {
                    item.GuestID,
                    item.CompanyName,
                    item.FirstName,
                    LastName = item.Lastname,
                    item.AddressLine1,
                    item.AddressLine2,
                    item.CountryID,
                    item.City,
                    item.ZipCode,
                    item.Email,
                    item.Tel,
                    item.Fax
                });

            return fetchAgent;
        }

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public GridTable<ViewReservation> GetReservationList(string bookingCode, string boatID, int status,
            int clientType, int routeNumber, char? subRouteCode, DateTime? fromDepartureDate, DateTime? toDepartureDate,
            DateTime? fromCreatedDate, DateTime? toCreatedDate, int pageSize, int pageNumber)
        {
            int totalRecords;
            var hs = new HashSet<string>();

            List<ViewReservation> reservationobjects =
                ReservationDAO.CreateInstant()
                    .GetViewReservation(fromDepartureDate, toDepartureDate, fromCreatedDate, toCreatedDate, bookingCode,
                        boatID, status, clientType, routeNumber, subRouteCode, pageNumber, pageSize, out totalRecords,
                        hs);

            var viewReservationList = new GridTable<ViewReservation>
            {
                PageNumber = pageNumber,
                TotalRecords = totalRecords,
                PageSize = pageSize,
                List = reservationobjects
            };

            return viewReservationList;
        }

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public IList<ViewReservation> ExportReservationList(string bookingCode, string boatID, int status,
            int clientType, int routeNumber, char? subRouteCode, DateTime? fromDepartureDate, DateTime? toDepartureDate,
            DateTime? fromCreatedDate, DateTime? toCreatedDate)
        {
            int totalRecords;
            var hs = new HashSet<string>();

            List<ViewReservation> reservationexcels =
                ReservationDAO.CreateInstant()
                    .GetViewReservation(fromDepartureDate, toDepartureDate, fromCreatedDate, toCreatedDate, bookingCode,
                        boatID, status, clientType, routeNumber, subRouteCode, null, null, out totalRecords, hs);

            return reservationexcels;
        }

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public bool CheckBookingCode(string bookingCode, string reservationId)
        {
            Guid guid;
            if (GuidUtils.TryParse(reservationId, out guid))
            {
                Reservation reservationEntity = ReservationDAO.CreateInstant().GetByReservationCode(bookingCode, guid);
                return (reservationEntity != null);
            }

            return false;
        }

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public object GetServiceCalendar(DateTime? departureDate)
        {
            if (departureDate == null)
                departureDate = DateTime.Today;

            departureDate = departureDate.Value.AddDays(-(int) departureDate.Value.DayOfWeek);

            object result = ReservationDAO.CreateInstant().GetServiceCalendar(departureDate.Value);

            object list = new
            {
                DayOfWeeks = new
                {
                    FirstDay = departureDate.Value.ToShortDate(),
                    SecondDay = departureDate.Value.AddDays(1).ToShortDate(),
                    ThirdDay = departureDate.Value.AddDays(2).ToShortDate(),
                    FourthDay = departureDate.Value.AddDays(3).ToShortDate(),
                    FifthDay = departureDate.Value.AddDays(4).ToShortDate(),
                    SixthDay = departureDate.Value.AddDays(5).ToShortDate(),
                    SeventhDay = departureDate.Value.AddDays(6).ToShortDate()
                },
                Result = result
            };

            return list;
        }

        #endregion

        #region Reservation

        /// <summary>
        ///     Check cabin available
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public bool CheckCabinAvaliable(bool isCharter, string boatID, string boardDateString, int noOfNights,
            int noOfCabins)
        {
            //bool result = false;
            DateTime boardDate = DateTime.Parse(boardDateString, CultureInfo.InvariantCulture);

            return CabinDAO.CreateInstant().GetCabinBoat(isCharter, boatID, boardDate, noOfNights, noOfCabins) != null;
        }

        /// <summary>
        ///     Get avaliable cabins
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public IList<ViewCabinBoat> GetAvailableCabins(string boatID, string boardDateString, int noOfNights,
            string cabins)
        {
            //bool result = false;
            DateTime boardDate = DateTime.Parse(boardDateString, CultureInfo.InvariantCulture);

            IList<string> cabinIDs;
            if (cabins.Length > 0)
            {
                // Skip the first comma (,)
                cabinIDs = cabins.Substring(1).Split(',');
            }
            else
            {
                cabinIDs = new List<string>();
            }
            return CabinDAO.CreateInstant().GetAvailableCabins(boatID, boardDate, noOfNights, cabinIDs);
        }

        /// <summary>
        ///     Get price route and type of cabin
        /// </summary>
        /// <returns></returns>
        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public long GetPrices(string priceType, string agentID, int routeNumber, int typeOfCabin, int numDate,
            string boatId)
        {
            // By Route and TypeOfCabin
            long result = 0;
            AgentPricesEntity item = AgentPricesDAO.CreateInstant()
                .GetAgentPrice(priceType, agentID, routeNumber, typeOfCabin, boatId);
            if (item != null)
                result = item.Price*numDate;
            return result;
        }

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public object GetShuttleAndCharter(string agentID, string boatID)
        {
            List<AgentPricesEntity> prices = AgentPricesDAO.CreateInstant().GetPrices(agentID);
            if (prices != null)
            {
                AgentPricesEntity priceShuttle = prices.SingleOrDefault(n => n.PriceType.Equals("shuttle"));
                long shuttlePrice = priceShuttle == null ? 0 : priceShuttle.Price;
                AgentPricesEntity priceCharter =
                    prices.SingleOrDefault(n => n.PriceType.Equals("charter") && n.Boat.Equals(boatID));
                long charterPrice = priceCharter == null ? 0 : priceCharter.Price;
                return new {ShuttlePrice = shuttlePrice, CharterPrice = charterPrice};
            }
            return null;
        }

        [WebMethod(EnableSession = true)]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public object GetPaymentList(Guid reservaiontID)
        {
            IList<PaymentBatchDTO> payments = PaymentBatchDAO.CreateInstant().GetPaymentList(reservaiontID);

            object list = new
            {
                List = payments
            };

            return list;
        }

        [WebMethod(EnableSession = true)]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public object GetExtraServices(Guid reservaiontID)
        {
            IList<ReservationExtra> extras = ReservationExtraDAO.CreateInstant().GetExtraServices(reservaiontID);

            object list = new
            {
                List = extras
            };

            return list;
        }

        #endregion

        #region ReservationServices

        [WebMethod(EnableSession = true)]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public object GetProgram(int routeNumber, char? subRouteCode, string boardingDate)
        {
            DateTime boardDate = DateTime.Parse(boardingDate, CultureInfo.InvariantCulture);

            IList<ReservationServiceDTO> serviceobjects = ServiceDAO.CreateInstant()
                .GetServicesBy(routeNumber, subRouteCode, boardDate);

            // Update Exchange Rate and Amount
            foreach (ReservationServiceDTO item in serviceobjects)
            {
                item.Rate =
                    (GetExchange(((CurrencyEnum) item.Currency).GetStringValue(),
                        item.ModifiedDate.HasValue ? item.ModifiedDate.Value.ToShortDate() : DateTime.Now.ToShortDate())
                        as ExchangeRate).UnitPrice;
            }

            object list = new
            {
                List = serviceobjects
            };

            return list;
        }

        [WebMethod(EnableSession = true)]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public object GetReservationServices(Guid reservationID)
        {
            IList<ReservationServiceDTO> serviceobjects = ServiceDAO.CreateInstant().GetServicesBy(reservationID);

            object list = new
            {
                List = serviceobjects
            };

            return list;
        }

        #endregion

        #region Services

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public ServiceDTO GetService(Guid serviceID)
        {
            return ServiceDAO.CreateInstant().Get(serviceID);
        }

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public bool ExistsService(string serviceCode)
        {
            return ServiceDAO.CreateInstant().Get(serviceCode) != null;
        }

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public GridTable<Service> GetServiceList(string serviceCode, string serviceName, int pageSize, int pageNumber)
        {
            int totalRecords = 0;
            var hs = new HashSet<string>();

            IList<Service> serviceobjects = ServiceDAO.CreateInstant()
                .GetServices(serviceCode, serviceName, pageNumber, pageSize, out totalRecords, hs);

            var serviceList = new GridTable<Service>
            {
                PageNumber = pageNumber,
                TotalRecords = totalRecords,
                PageSize = pageSize,
                List = serviceobjects,
                IsAdmin = HttpContext.Current.User.IsInRole(define.AdminRole)
            };

            return serviceList;
        }

        #endregion

        #region Route

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public RouteDTO GetRoute(Guid routeID)
        {
            return RouteDAO.CreateInstant().GetRoute(routeID);
        }

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public bool ExistsRoute(int routeNumber, char? subRouteCode)
        {
            return RouteDAO.CreateInstant().GetRoute(routeNumber, subRouteCode) != null;
        }

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public GridTable<Route> GetRouteList(string routeNumber, string routeName, int pageNumber)
        {
            int totalRecords = 0;
            var hs = new HashSet<string>();
            hs.Add("RouteNumber");

            IList<Route> routeobjects = RouteDAO.CreateInstant()
                .GetRoutes(routeNumber, routeName, pageNumber, define.PageSize, out totalRecords, hs);

            var routeList = new GridTable<Route>
            {
                PageNumber = pageNumber,
                TotalRecords = totalRecords,
                PageSize = define.PageSize,
                List = routeobjects,
                IsAdmin = HttpContext.Current.User.IsInRole(define.AdminRole)
            };

            return routeList;
        }

        #endregion

        #region Provider

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public ProviderDTO GetProvider(Guid providerID)
        {
            return ProviderDAO.CreateInstant().Get(providerID);
        }

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public bool ExistsProvider(string providerNumber)
        {
            return ProviderDAO.CreateInstant().Get(providerNumber) != null;
        }

        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public GridTable<ProviderEntity> GetProviderList(string providerNumber, string providerName, string email,
            string website, string addressLine, string city, string phone, string faxNumber, int pageSize,
            int pageNumber)
        {
            int totalRecords = 0;
            var hs = new HashSet<string>();

            IList<ProviderEntity> providerobjects = ProviderDAO.CreateInstant()
                .GetProviders(providerNumber, providerName, email, website, addressLine, city, phone, faxNumber,
                    pageNumber, pageSize, out totalRecords, hs);

            var providerList = new GridTable<ProviderEntity>
            {
                PageNumber = pageNumber,
                TotalRecords = totalRecords,
                PageSize = pageSize,
                List = providerobjects,
                IsAdmin = HttpContext.Current.User.IsInRole(define.AdminRole)
            };

            return providerList;
        }

        #endregion

        #region Location

        /// <summary>
        ///     Get All Location
        /// </summary>
        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public GridTable<Location> GetAllLocation(int pageNumber)
        {
            int totalRecords = 0;
            var hs = new HashSet<string>();
            hs.Add("LocationName");

            IList<Location> locationList = LocationDAO.CreateInstant()
                .GetLocations(pageNumber, define.PageSize, out totalRecords, hs);

            var gridLocation = new GridTable<Location>
            {
                PageNumber = pageNumber,
                TotalRecords = totalRecords,
                PageSize = define.PageSize,
                List = locationList,
                IsAdmin = HttpContext.Current.User.IsInRole(define.AdminRole)
            };

            return gridLocation;
        }

        /// <summary>
        ///     Get All Location
        /// </summary>
        [WebMethod]
        [PrincipalPermission(SecurityAction.Demand, Authenticated = true)]
        public Location GetLocation(int locationID)
        {
            return LocationDAO.CreateInstant().GetLocation(locationID);
        }

        #endregion

        #region Shared Methods

        private bool ExportExcel(object dataSource, string filename)
        {
            bool result = false;
            try
            {
                string attachment = "attachment; filename=" + filename + ".xls";
                //HttpContext.Current.Response.ClearContent();
                HttpContext.Current.Response.Clear();
                HttpContext.Current.Response.Buffer = true;
                HttpContext.Current.Response.AddHeader("content-disposition", attachment);
                HttpContext.Current.Response.ContentType = "application/vnd.ms-excel";
                HttpContext.Current.Response.Charset = "";
                HttpContext.Current.Response.ContentEncoding = Encoding.Unicode;
                HttpContext.Current.Response.BinaryWrite(Encoding.Unicode.GetPreamble());

                var stw = new StringWriter();
                var htextw = new HtmlTextWriter(stw);

                var gridView = new GridView();
                gridView.DataSource = dataSource;
                gridView.DataBind();
                gridView.RenderControl(htextw);

                HttpContext.Current.Response.Write(stw.ToString());
                HttpContext.Current.Response.End();

                result = true;
            }
            catch (Exception ex)
            {
                throw ex;
            }

            return result;
        }

        #endregion
    }

    public class GridTable<T>
    {
        public int PageNumber { get; set; }
        public int TotalRecords { get; set; }
        public int PageSize { get; set; }
        public IList<T> List { get; set; }
        public bool IsAdmin { get; set; }
    }

    public class ObjectT
    {
        public string label { get; set; }
        public string category { get; set; }
    }
}